package org.jeecg.modules.bpm.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.bpmn.behavior.ParallelGatewayActivityBehavior;
import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.DelegationState;
import org.activiti.engine.task.Task;
import org.apache.commons.lang.StreamUtils;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.bpm.config.BpmGlobals;
import org.jeecg.modules.bpm.dto.ActHiActinstDTO;
import org.jeecg.modules.bpm.dto.ProcessHisDTO;
import org.jeecg.modules.bpm.dto.TaskDTO;
import org.jeecg.modules.bpm.model.diagram.HistoryProcessInstanceDiagramCmd;
import org.jeecg.modules.bpm.model.diagram.HistoryProcessInstanceDiagramPositionCmd;
import org.jeecg.modules.bpm.service.ActivitiService;
import org.jeecg.modules.bpm.util.XmlActivitiUtil;
import org.jeecg.modules.extbpm.process.common.WorkFlowGlobals;
import org.jeecg.modules.extbpm.process.entity.ExtActBpmFile;
import org.jeecg.modules.extbpm.process.entity.ExtActBpmLog;
import org.jeecg.modules.extbpm.process.entity.ExtActFlowData;
import org.jeecg.modules.extbpm.process.entity.ExtActTaskCc;
import org.jeecg.modules.extbpm.process.exception.BpmException;
import org.jeecg.modules.extbpm.process.service.*;
import org.jeecg.modules.extbpm.util.CommonRandomUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 *   流程任务管理
 *
 * @ClassName: TaskController
 * @author scott
 * @date 2012-8-19 下午04:20:06
 *
 */
@Slf4j
@RestController("actTaskController")
@RequestMapping("/act/task")
public class ActTaskController {
	@Autowired
	protected RepositoryService repositoryService;
	@Autowired
	protected RuntimeService runtimeService;
	@Autowired
	protected TaskService taskService;
	@Autowired
	protected IdentityService identityService;
	@Autowired
	private ActivitiService activitiService;
	@Autowired
	private IExtActBpmLogService extActBpmLogService;
	@Autowired
	private HistoryService historyService;
	@Autowired
	private IExtActTaskCcService extActTaskCcService;
	@Autowired
	private IExtActBpmFileService extActBpmFileService;
	@Autowired
	private ISysBaseAPI sysBaseAPI;
	@Autowired
	private IExtActFlowDataService extActFlowDataService;
	@Autowired
	private IExtActProcessService extActProcessService;

	/**
	 * 待办任务列表-我的任务
	 */
	@GetMapping(value = "/list")
	public Result<IPage<TaskDTO>> list(HttpServletRequest request) {
		log.debug("------------进入list---------------");
		long time1=System.currentTimeMillis();
		Result<IPage<TaskDTO>> result = new Result<IPage<TaskDTO>>();
		IPage<TaskDTO> pageList = new Page<TaskDTO>();

		String userid = JwtUtil.getUserNameByToken(request); // 获取当前登录用户
		List<TaskDTO> records = activitiService.findPriTodoTasks(userid, request);
		long time2=System.currentTimeMillis();
		log.info("获取我的任务分页列表 耗时："+(time2-time1)+"ms");
		Long taskTotalSize = activitiService.countPriTodaoTask(userid, request);
		log.info("taskTotalSize：" + taskTotalSize);
		log.info("获取我的任务总数  耗时："+(System.currentTimeMillis()-time2)+"ms");
		pageList.setRecords(records);
		pageList.setTotal(taskTotalSize);
		result.setSuccess(true);
		result.setResult(pageList);
		log.debug("-----	-------退出list---------------");
		return result;
	}

	/**
	 * 待办任务列表-用户所有的任务
	 */
	@GetMapping(value = "/taskGroupList")
	public Result<IPage<TaskDTO>> taskGroupList(HttpServletRequest request) {
		Result<IPage<TaskDTO>> result = new Result<IPage<TaskDTO>>();
		IPage<TaskDTO> pageList = new Page<TaskDTO>();

		String username = JwtUtil.getUserNameByToken(request); // 获取当前登录用户
		//根据用户获取当前用户所属的角色
		List<String> roles = sysBaseAPI.getRolesByUsername(username);
		List<TaskDTO> records = activitiService.findGroupTodoTasks(roles, request);
		Long taskSize = activitiService.countGroupTodoTasks(roles, request);
		log.info("taskSize：" + taskSize);

		pageList.setRecords(records);
		pageList.setTotal(taskSize);
		result.setSuccess(true);
		result.setResult(pageList);
		return result;
	}


	/**
	 * 待办任务列表-历史任务
	 */
	@GetMapping(value = "/taskHistoryList")
	public Result<IPage<TaskDTO>> taskHistoryList(HttpServletRequest request,
			@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
			  @RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
		Result<IPage<TaskDTO>> result = new Result<IPage<TaskDTO>>();
		Page<TaskDTO> pageList = new Page<TaskDTO>(pageNo,pageSize);
		String userid = JwtUtil.getUserNameByToken(request); // 获取当前登录用户
		//根据用户获取当前用户所属的角色
		pageList = activitiService.findHistoryTasks(pageList,userid, request);
		result.setSuccess(true);
		result.setResult(pageList);
		return result;
	}

	/**
	 *	根据任务id获取流程任务流转信息
	 * @param id
	 * @return
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	@GetMapping(value = "/getProcessTaskTransInfo")
	public Result<Map<String,Object>> getProcessTaskTransInfo(@RequestParam(name="taskId",required=true) String taskId) {
		Result<Map<String,Object>> result = new Result<Map<String,Object>>();
		Task  task = activitiService.getTask(taskId);
		Map<String,Object> map = new HashMap<String,Object>();
		//流程下一步节点操作
		List<Map> transList = activitiService.getOutTransitions(taskId);
		//判断一下任务节点后续的分支，是否只有一个，如果是且分支的路线中文名字没有的话，默认为提交
		if(transList.size()==1){
			for(Map t:transList){
				t.put("Transition", "确认提交");
			}
		}
		//流程分支
		map.put("transitionList", transList);
		//下一步节点数目
		map.put("nextCodeCount", transList==null?0:transList.size());
		//历史任务节点
		List<Map<String,Object>> histListNode = activitiService.getHistTaskNodeList(task.getProcessInstanceId());
		map.put("histListNode", histListNode);
		map.put("histListSize", histListNode.size());
		//获取上一步的节点
		String turnbackTaskId = getTurnbackTaskId(task,histListNode);
		log.info("turnbackTaskId======>"+turnbackTaskId);
		map.put("turnbackTaskId", turnbackTaskId);

		map.put("taskId", taskId);
		map.put("taskName", task.getName());
		String taskAssigneeName = "";
		String taskNameStartTime = "";
		if(task!=null&&CommonRandomUtil.isNotEmpty(task.getAssignee())){
			LoginUser user = sysBaseAPI.getUserByName(task.getAssignee());
			if(user!=null){
				taskAssigneeName = user.getRealname();
			}
			taskNameStartTime = task.getCreateTime()==null?"":DateUtils.formatDate(task.getCreateTime(), "YYYY-MM-dd HH:mm:ss");
		}
		map.put("taskAssigneeName", taskAssigneeName);
		map.put("taskNameStartTime", taskNameStartTime);
		// 流程审批日志
		List<ExtActBpmLog> bpmLogList = new ArrayList<ExtActBpmLog>();
		LambdaQueryWrapper<ExtActBpmLog> queryWrapper = new LambdaQueryWrapper<ExtActBpmLog>();
		queryWrapper.eq(ExtActBpmLog::getProcInstId, task.getProcessInstanceId());
        //--update--begin------author:scott-----date:20190909-----for:任务办理，时间轴进度条不展示定时任务自动委派---------------
		queryWrapper.ne(ExtActBpmLog::getOpUserId, WorkFlowGlobals.SYS_AGENT_JOB_OPUSER_ID);
        //--update--end------author:scott-----date:20190909-----for:任务办理，时间轴进度条不展示定时任务自动委派-----------------
		queryWrapper.orderByAsc(ExtActBpmLog::getOpTime);
		bpmLogList = extActBpmLogService.list(queryWrapper);
		List<ExtActBpmFile> fileList = null;
		for(ExtActBpmLog bpmlog:bpmLogList) {
			LambdaQueryWrapper<ExtActBpmFile> queryWrapperFile = new LambdaQueryWrapper<ExtActBpmFile>();
			queryWrapperFile.eq(ExtActBpmFile::getBpmLogId, bpmlog.getId());
			fileList = extActBpmFileService.list(queryWrapperFile);
			bpmlog.setBpmFiles(fileList);
		}
		int fromIndex = 0;
		int toIndex = 0;
		if(bpmLogList.size()-3>0){
			fromIndex = bpmLogList.size() - 3;
			toIndex =  bpmLogList.size();
		}else{
			fromIndex = 0;
			toIndex =  bpmLogList.size();
		}
		List bpmLogStepList = bpmLogList.subList(fromIndex, toIndex);
		map.put("bpmLogList", bpmLogList);
		map.put("bpmLogListCount",bpmLogList.size());
		map.put("bpmLogStepList", bpmLogStepList);
		map.put("bpmLogStepListCount", bpmLogStepList.size());

		result.setResult(map);
		result.setSuccess(true);
		return result;
	}

	/**
	 *	根据任务id获取流程任务流转信息
	 * @param id
	 * @return
	 */
	@SuppressWarnings({ "rawtypes" })
	@GetMapping(value = "/getHisProcessTaskTransInfo")
	public Result<Map<String,Object>> getHisProcessTaskTransInfo(@RequestParam(name="procInstId",required=true) String procInstId) {
		Result<Map<String,Object>> result = new Result<Map<String,Object>>();
		Map<String,Object> map = new HashMap<String,Object>();
		//判断是否有结束节点，没有则说明流程未结束，展示当前节点
		List<ActHiActinstDTO> startAndEndlist = activitiService.getActHiActinstStartAndEnd(procInstId);
		boolean flag = false;
		ExtActBpmLog endNodeLog = new ExtActBpmLog();
		//结束节点
        for(ActHiActinstDTO m:startAndEndlist){
        	if("endEvent".equals(m.getActType())){
        		flag = true;
				//--update--begin------author:scott-----date:20200103-----for:流程办理页面，流程结束情况下，办理进度条增加一个结束节点----------------
				endNodeLog.setTaskName("结束");
				endNodeLog.setOpTime(m.getEndTime());
				//获取流程结束办理人
				List<Map<String,Object>> taskinstList = activitiService.getProcessEndUserId(procInstId);
				if(taskinstList!=null){
					Map<String,Object> mp = taskinstList.get(0);
					String assignee_ = oConvertUtils.getString(mp.get("ASSIGNEE_"));
					if(oConvertUtils.isNotEmpty(assignee_)) {
						LoginUser sysUser = sysBaseAPI.getUserByName(assignee_);
						endNodeLog.setOpUserName(sysUser!=null?sysUser.getRealname():assignee_);
					}
				}
				//--update--begin------author:scott-----date:20200103-----for:流程办理页面，流程结束情况下，办理进度条增加一个结束节点---------------
        		break;
        	}
        }
        String currTaskName = null;
        String currTaskNameAssignee = null;
        String currTaskNameStartTime = null;
        //流程未结束,获取流程历史,获取当前流程
        if(!flag){
        	List<HistoricTaskInstance> historicTasks = historyService.createHistoricTaskInstanceQuery().processInstanceId(procInstId).list();
        	if(historicTasks!=null&&historicTasks.size()>0){
        		HistoricTaskInstance hisTask= historicTasks.get(historicTasks.size()-1);
        		currTaskName = hisTask.getName();
        		if(oConvertUtils.isNotEmpty(hisTask.getAssignee())) {
        			LoginUser user = sysBaseAPI.getUserByName(hisTask.getAssignee());
        			currTaskNameAssignee= user.getRealname();
        		}
        		currTaskNameStartTime = hisTask.getStartTime()==null?"":DateUtils.formatDate(hisTask.getStartTime(), "YYYY-MM-dd HH:mm:ss");
        	}

        }
        map.put("currTaskName", currTaskName);
        map.put("currTaskNameAssignee", currTaskNameAssignee);
        map.put("currTaskNameStartTime", currTaskNameStartTime);

		// 流程审批日志
		List<ExtActBpmLog> bpmLogList = new ArrayList<ExtActBpmLog>();
		LambdaQueryWrapper<ExtActBpmLog> queryWrapper = new LambdaQueryWrapper<ExtActBpmLog>();
		queryWrapper.eq(ExtActBpmLog::getProcInstId, procInstId);
        //--update--begin------author:scott-----date:20190909-----for:任务办理，时间轴进度条不展示定时任务自动委派---------------
		queryWrapper.ne(ExtActBpmLog::getOpUserId, WorkFlowGlobals.SYS_AGENT_JOB_OPUSER_ID);
        //--update--end------author:scott-----date:20190909-----for:任务办理，时间轴进度条不展示定时任务自动委派---------------
		queryWrapper.orderByAsc(ExtActBpmLog::getOpTime);
		bpmLogList = extActBpmLogService.list(queryWrapper);
		List<ExtActBpmFile> fileList = null;
		for(ExtActBpmLog bpmlog:bpmLogList) {
			LambdaQueryWrapper<ExtActBpmFile> queryWrapperFile = new LambdaQueryWrapper<ExtActBpmFile>();
			queryWrapperFile.eq(ExtActBpmFile::getBpmLogId, bpmlog.getId());
			fileList = extActBpmFileService.list(queryWrapperFile);
			bpmlog.setBpmFiles(fileList);
		}

		//--update--begin------author:scott-----date:20200103-----for:流程办理页面，流程结束情况下，办理进度条增加一个结束节点---------------
		//判断流程状态，已经结束，额外增加一个结束日志
		if(flag){
			bpmLogList.add(endNodeLog);
		}
		//--update--end------author:scott-----date:20200103-----for:流程办理页面，流程结束情况下，办理进度条增加一个结束节点---------------

		int skipIndex = bpmLogList.size() - 3 < 0 ? 0 : bpmLogList.size() - 3;
		List bpmLogStepList = bpmLogList.stream().skip(skipIndex).collect(Collectors.toList());
		log.info("bpmLogStepList size : "+ bpmLogStepList.size());
		map.put("bpmLogList", bpmLogList);
		map.put("bpmLogListCount",bpmLogList.size());
		map.put("bpmLogStepList", bpmLogStepList);
		map.put("bpmLogStepListCount", bpmLogStepList.size());

		result.setResult(map);
		result.setSuccess(true);
		return result;
	}


	//获取退回的上个节点
	private String getTurnbackTaskId(Task task,List<Map<String,Object>> histListNode){
		String turnbackTaskId = "";
		List<String> taskIdList = new ArrayList<String>();
		List<ActivityImpl> actList = getInTask(task);
		//找出走过的上个节点
		if(histListNode!=null&&histListNode.size()>0){
			for(int i=histListNode.size();i>0;i--){
				Map<String,Object> map = histListNode.get(i-1);
				if(actList!=null&&actList.size()>0){
					for(ActivityImpl act :actList){
						if(act.getId().equals((String)map.get("task_def_key_"))){
							taskIdList.add(act.getId());
							break;
						}
					}
				}
			}
		}
		if(taskIdList.size()>0){
			turnbackTaskId = taskIdList.get(0);
		}
		return turnbackTaskId;
	}

	//获取来源节点
	private List<ActivityImpl> getInTask(Task task){
		List<ActivityImpl> list = new ArrayList<ActivityImpl>();
		 // 取得流程定义
        ProcessDefinitionEntity definition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(task
                        .getProcessDefinitionId());
		// 取得上一步活动
        ActivityImpl currActivity = ((ProcessDefinitionImpl) definition)
                .findActivity(task.getTaskDefinitionKey());
        if(currActivity.getActivityBehavior() instanceof SequentialMultiInstanceBehavior){
        	//顺序会签节点不能回退
        }else if(currActivity.getActivityBehavior() instanceof ParallelMultiInstanceBehavior){
        	//并行会签节点不能回退
        }else{
        	list.addAll(getInTaskByAct(currActivity));
        }
        return list;
	}


	private List<ActivityImpl> getInTaskByAct(ActivityImpl act){
		List<ActivityImpl> list = new ArrayList<ActivityImpl>();
        //也就是节点间的连线
        List<PvmTransition> inTransitionList = act.getIncomingTransitions();
        for(PvmTransition pvm:inTransitionList){
        	ActivityImpl t = (ActivityImpl)pvm.getSource();
        	if(t.getActivityBehavior() instanceof UserTaskActivityBehavior){
        		list.add(t);
        	}else if(t.getActivityBehavior() instanceof ParallelGatewayActivityBehavior){
        		//上个节点是并行网关 不回退
        		break;
        	}else{
        		list.addAll(getInTaskByAct(t));
        	}
        }
        return list;
	}

	/**
	 * 读取带跟踪的流程图片
	 * @throws Exception
	 */
	@GetMapping(value = "traceImage")
    public void traceImage(@RequestParam("processInstanceId") String processInstanceId,
    		HttpServletResponse response) throws Exception {
		InputStream is =null;
		try {
			Command<InputStream> cmd = new HistoryProcessInstanceDiagramCmd(processInstanceId);
			ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
			is = processEngine.getManagementService().executeCommand(cmd);

			int len = 0;
			byte[] b = new byte[1024];

			while ((len = is.read(b, 0, 1024)) != -1) {
				response.getOutputStream().write(b, 0, len);
			}
			response.getOutputStream().flush();
			response.getOutputStream().close();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				if(is!=null){
					is.close();
				}
			} catch (Exception e) {
			}
		}
    }

	/**
	 * 读取带跟踪的流程图片
	 * @throws Exception
	 */
	@GetMapping(value = "getNodePositionInfo")
    public Result<Map<String,Object>> getNodePositionInfo(@RequestParam("processInstanceId") String processInstanceId,
    		HttpServletResponse response) throws Exception {
		Result<Map<String,Object>> result = new Result<Map<String,Object>>();
		Map<String,Object> map = new HashMap<String,Object>();
		List<HistoricTaskInstance> historicTasks = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).list();
		List<TaskDTO> taskList = new ArrayList<TaskDTO>();
		TaskDTO task = null;
		ExtActBpmLog log = null;
		for(HistoricTaskInstance hi:historicTasks) {
			task = new TaskDTO();
			task.setId(hi.getId());
			task.setTaskId(hi.getTaskDefinitionKey());
			task.setTaskBeginTime(hi.getStartTime());
			task.setTaskEndTime(hi.getEndTime());
			task.setTaskAssigneeId(hi.getAssignee());
			task.setTaskDueTime(hi.getDurationInMillis());
			task.setTaskName(hi.getName());

			//---update-begin-----autor:scott------date:20191203------for:流程图鼠标点击展示任务办理卡片，增加返回办理人真实名字字段
			LoginUser loginUser = sysBaseAPI.getUserByName(hi.getAssignee());
			if(loginUser!=null){
				task.setTaskAssigneeName(loginUser.getRealname());
			}
			//---update-end-----autor:scott------date:20191203------for:流程图鼠标点击展示任务办理卡片，增加返回办理人真实名字字段

			//查询审批意见，根据任务id查询

			LambdaQueryWrapper<ExtActBpmLog> queryWrapper = new LambdaQueryWrapper<ExtActBpmLog>();
			queryWrapper.eq(ExtActBpmLog::getTaskId, hi.getId());
			List<ExtActBpmLog> list = extActBpmLogService.list(queryWrapper);
			if(list!=null&&list.size()>0) {
				log = list.get(0);
				task.setRemarks(log.getRemarks());
			}
			taskList.add(task);
		}
		map.put("hisTasks", taskList);
		Command cmd = new HistoryProcessInstanceDiagramPositionCmd(processInstanceId);
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
		List<ActivityImpl> is = (List<ActivityImpl>)processEngine.getManagementService().executeCommand(cmd);
		List<Map<String,Object>> dataList = new ArrayList<Map<String,Object>>();
		Map<String,Object> actData = null;
		for(ActivityImpl activityImpl:is){
			actData = new HashMap<String,Object>();
			actData.put("x", activityImpl.getX());
			actData.put("y", activityImpl.getY());
			actData.put("width", activityImpl.getWidth());
			actData.put("height", activityImpl.getHeight());
			actData.put("id", activityImpl.getId());
			String coords = activityImpl.getX()
					+","+activityImpl.getY()
					+","+(activityImpl.getX()+activityImpl.getWidth())
					+","+(activityImpl.getY()+activityImpl.getHeight());
			actData.put("coords", coords);
			dataList.add(actData);
		}
		map.put("positionList", dataList);
		result.setResult(map);
		result.setSuccess(true);
		return result;
    }


	/**
	 * 流程历史数据获取
	 */
	@GetMapping(value = "/processHistoryList")
	public Result<IPage<ProcessHisDTO>> processHistoryList(@RequestParam("processInstanceId") String processInstanceId,
															HttpServletRequest request) {
		Result<IPage<ProcessHisDTO>> result = new Result<IPage<ProcessHisDTO>>();
		IPage<ProcessHisDTO> pageList = new Page<ProcessHisDTO>();
		List<ProcessHisDTO> records = new ArrayList<ProcessHisDTO>();
		List<ActHiActinstDTO> startAndEndlist = activitiService.getActHiActinstStartAndEnd(processInstanceId);
		List<HistoricTaskInstance> historicTasks = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).list();
		String startUserId = activitiService.getProcessStartUserId(processInstanceId);
		String endUserId = "";
        List<Map<String,Object>> taskinstList = activitiService.getProcessEndUserId(processInstanceId);
        if(taskinstList!=null){
        	Map<String,Object> map = taskinstList.get(0);
        	if(map!=null) {
        		endUserId = map.get("ASSIGNEE_")==null?"":(String)map.get("ASSIGNEE_");
        	}
        }
        //开启节点
        ProcessHisDTO dto = null;
        for(ActHiActinstDTO actHiActinstDTO:startAndEndlist){
        	if("startEvent".equals(actHiActinstDTO.getActType())){
        		String startTime =actHiActinstDTO.getStartTime()==null?"":DateUtils.formatDate(actHiActinstDTO.getStartTime(), "yyyy-MM-dd HH:mm:ss");
        		String endTime = actHiActinstDTO.getEndTime()==null?"":DateUtils.formatDate(actHiActinstDTO.getEndTime(), "yyyy-MM-dd HH:mm:ss");
        		dto = new ProcessHisDTO();
        		dto.setId(WorkFlowGlobals.BPM_NODE_START);
        		dto.setName(actHiActinstDTO.getActId());
        		dto.setProcessInstanceId(actHiActinstDTO.getExecutionId());
        		dto.setStartTime(startTime);
        		dto.setEndTime(endTime);
        		dto.setAssignee(startUserId);
        		if(oConvertUtils.isNotEmpty(dto.getAssignee())) {
        			LoginUser sysUser = sysBaseAPI.getUserByName(dto.getAssignee());
        			dto.setAssigneeName(sysUser!=null?sysUser.getRealname():dto.getAssignee());
        		}
        		dto.setDeleteReason("已完成");
        		records.add(dto);
        	}
        }

        for(HistoricTaskInstance hi : historicTasks){
        	String reason = "";
        	if("completed".equals(hi.getDeleteReason())){
        		reason = "已完成";
        		if(hi.getDescription()!=null&&hi.getDescription().indexOf("委托")!=-1){
        			reason =hi.getDescription()+"【"+reason+"】";
        		}
        	}else{
        		reason = hi.getDeleteReason();
        	}
        	String startTime = hi.getStartTime()==null?"":DateUtils.formatDate(hi.getStartTime(), "yyyy-MM-dd HH:mm:ss");
        	String endTime = hi.getEndTime()==null?"":DateUtils.formatDate(hi.getEndTime(), "yyyy-MM-dd HH:mm:ss");
			dto = new ProcessHisDTO();
			dto.setId(hi.getId());
    		dto.setName(hi.getName());
    		dto.setProcessInstanceId(hi.getProcessInstanceId());
    		dto.setStartTime(startTime);
    		dto.setEndTime(endTime);
    		dto.setAssignee(hi.getAssignee());
    		if(oConvertUtils.isNotEmpty(dto.getAssignee())) {
    			LoginUser sysUser = sysBaseAPI.getUserByName(dto.getAssignee());
    			dto.setAssigneeName(sysUser!=null?sysUser.getRealname():dto.getAssignee());
    		}
    		dto.setDeleteReason(reason);
    		records.add(dto);
        }

        //结束节点
        for(ActHiActinstDTO actHiActinstDTO:startAndEndlist){
        	if("endEvent".equals(actHiActinstDTO.getActType())){
        		String startTime =actHiActinstDTO.getStartTime()==null?"":DateUtils.formatDate(actHiActinstDTO.getStartTime(), "yyyy-MM-dd HH:mm:ss");
        		String endTime = actHiActinstDTO.getEndTime()==null?"":DateUtils.formatDate(actHiActinstDTO.getEndTime(), "yyyy-MM-dd HH:mm:ss");
        		dto = new ProcessHisDTO();
        		dto.setId(WorkFlowGlobals.BPM_NODE_START);
        		dto.setName(actHiActinstDTO.getActId());
        		dto.setProcessInstanceId(actHiActinstDTO.getExecutionId());
        		dto.setStartTime(startTime);
        		dto.setEndTime(endTime);
        		dto.setAssignee(endUserId);
        		if(oConvertUtils.isNotEmpty(dto.getAssignee())) {
        			LoginUser sysUser = sysBaseAPI.getUserByName(dto.getAssignee());
        			dto.setAssigneeName(sysUser!=null?sysUser.getRealname():dto.getAssignee());
        		}
        		dto.setDeleteReason("已完成");
        		records.add(dto);
        	}
        }

		log.info("taskSize：" + records.size());
		pageList.setRecords(records);
		pageList.setTotal((long)records.size());
		result.setSuccess(true);
		result.setResult(pageList);
		return result;
	}


	@PostMapping(value = "processComplete")
	public Result<Object> processComplete(@RequestBody HashMap<String, String> map,
											HttpServletRequest request) {
		Result<Object> result = new Result<Object>();
		try {
			//监听通过request取到参数的信息的处理
			request.setAttribute("data", map);
			String taskId = oConvertUtils.getString(map.get("taskId"));
			//下一节点名称
			String nextnode = oConvertUtils.getString(map.get("nextnode"));
			//下一步节点的数目（小心歧义）
			Integer nextCodeCount = oConvertUtils.getInt(map.get("nextCodeCount"));
//		String way = oConvertUtils.getString(request.getParameter("way"));
//		ProcessHandle processHandle = activitiService.getProcessHandle(taskId);
			//模式类型（单/多分支模式/驳回模式）
			String model = oConvertUtils.getString(map.get("processModel"));
			//下一步操作人
			String nextUser = oConvertUtils.getString(map.get("nextUserId"));
			//驳回时选择驳回到哪一节点
			String rejectNode = oConvertUtils.getString(map.get("rejectModelNode"));
			//TODO 流程变量参数
//		Map<String, Object> varmap = var.getVariableMap(processHandle.getTpProcesspros());
			Map<String, Object> varmap = new HashMap<String, Object>();
			Task task = activitiService.getTask(taskId);
			String processInstanceId = task.getProcessInstanceId();
			runtimeService.setVariable(processInstanceId, WorkFlowGlobals.BPM_STATUS, WorkFlowGlobals.BPM_BUS_STATUS_2);
			boolean bflag = this.checkUserTaskIsHuiQian(taskId,nextnode);
			if(bflag){
				map.put(WorkFlowGlobals.ASSIGNEE_USER_ID_LIST, nextUser);
				runtimeService.setVariable(processInstanceId, WorkFlowGlobals.ASSIGNEE_USER_ID_LIST, nextUser);
			}
			//判断是否是委托任务，被委托人先解决委托
			if (StringUtils.isNotBlank(task.getOwner())) {
				DelegationState delegationState = task.getDelegationState();
	            switch (delegationState) {
	            case PENDING:
	                taskService.resolveTask(taskId);
	                break;
	            case RESOLVED:
	                //委托任务已经完成
	                break;

	            default:
	                //不是委托任务
	                break;
	            }
			}

			String rejectDescription ="";
			if("1".equals(model)){
				//---update-begin-----autor:zhoujf------date:20190927-------for:并行网关停滞不前问题--------
				//判断是否是并行网关
				boolean isParallelGateway = this.checkParallelGateway(task.getProcessDefinitionId(),nextnode);
				//单分支模式
				if("end".equals(nextnode)){
					if(nextCodeCount==1 || isParallelGateway){
						taskService.complete(taskId, varmap);
					}else{
						activitiService.goProcessTaskNode(taskId,nextnode,varmap);
					}
				}else{
					//多分支模式
					if(nextCodeCount==1 || isParallelGateway){
						taskService.complete(taskId, varmap);
					}else{
						activitiService.goProcessTaskNode(taskId,nextnode,varmap);
					}
					//---update-end-----autor:zhoujf------date:20190927-------for:并行网关停滞不前问题--------
					//如果下个节点不是会签节点，动态指派下一步处理人
					if(!bflag){
						//会签情况下，该SQL会报错
						String nextTskId = activitiService.getTaskIdByProins(processInstanceId, nextnode);
						//---update-begin-----autor:scott------date:20190925-------for:TASK #3188 下一步节点不是任务节点的情况下，不走指派逻辑不然报错。比如：下一步是个网关--------
						if(oConvertUtils.isNotEmpty(nextUser)&&oConvertUtils.isNotEmpty(nextTskId)){
						//---update-end-----autor:scott------date:20190925-------for:TASK #3188 下一步节点不是任务节点的情况下，不走指派逻辑不然报错。比如：下一步是个网关--------
							if(nextUser.indexOf(",") < 0){
								//指定单个执行人
								taskService.setAssignee(nextTskId,nextUser);
							}else{
								//---update-begin-----autor:scott------date:20190925-------for:TASK #3187 【疑似BUG】 出差申请 下一步操作人 选择多个
								//指定多人
								taskService.setAssignee(nextTskId,null);
								for (String userid : nextUser.split(",")) {
									if (oConvertUtils.isNotEmpty(userid)) {
										taskService.addCandidateUser(nextTskId, userid);
									}
								}
								//---update-end-----autor:scott------date:20190925-------for:TASK #3187 【疑似BUG】 出差申请 下一步操作人 选择多个
							}
						}
					}
				}
			}else if("2".equals(model)){
				//多分支模式
				taskService.complete(taskId, varmap);
			}else{
				runtimeService.setVariable(processInstanceId, WorkFlowGlobals.BPM_STATUS, WorkFlowGlobals.PROCESS_REJECTPROCESS_STATUS);
				//驳回模式
				activitiService.goProcessTaskNode(taskId,rejectNode,varmap);
				String nextTskId = activitiService.getTaskIdByProins(processInstanceId, rejectNode);
				if(oConvertUtils.isNotEmpty(nextUser)){
					if(nextUser.indexOf(",") < 0){
						//指定单个执行人
						taskService.setAssignee(nextTskId,nextUser);
					}else{
						//指定多人
						taskService.setAssignee(nextTskId,null);
						//---update-begin-----autor:scott------date:20190930------for:TASK #3187 【疑似BUG】 出差申请 下一步操作人 选择多个
						for (String userid : nextUser.split(",")) {
							if (oConvertUtils.isNotEmpty(userid)) {
								taskService.addCandidateUser(nextTskId, userid);
							}
						}
						//---update-end-----autor:scott------date:20190930-------for:TASK #3187 【疑似BUG】 出差申请 下一步操作人 选择多个
					}
				}
				//TODO  流程委托、驳回 日志问题
				Task nexttask = activitiService.getTask(nextTskId);
				//---update-begin-----autor:scott------date:20191203------for:驳回人显示真实名字，不显示账号
				String assigneeUserName = task.getAssignee();
				LoginUser loginUser = sysBaseAPI.getUserByName(task.getAssignee());
				if (loginUser != null) {
					assigneeUserName = loginUser.getRealname();
				}
				//---update-end-----autor:scott------date:20191203------for:驳回人显示真实名字，不显示账号

				rejectDescription = assigneeUserName +"驳回任务 〔"+task.getName()+"〕 →〔"+nexttask.getName()+"〕 ";
//				List<HistoricTaskInstance>  hiTaskInstList = historyService.createHistoricTaskInstanceQuery().taskId(taskId).list();
//				ActHiTaskinst actHiTaskinst = this.systemService.get(ActHiTaskinst.class, taskId);
//				actHiTaskinst.setDescription(rejectDescription);
//				actHiTaskinst.setDeleteReason(rejectDescription);
//				this.systemService.saveOrUpdate(actHiTaskinst);
				// 流程委托、驳回 日志问题
			}

			String username = JwtUtil.getUserNameByToken(request);
			LoginUser user = sysBaseAPI.getUserByName(username);
			// 任务抄送处理
			String ccUserNames = oConvertUtils.getString(map.get("ccUserIds"));
			//任务抄送记录
			taskCc(ccUserNames,task,username);

			//每个task节点执行完成后，处理审批日志
			ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();

			String reason = oConvertUtils.getString(map.get("reason"));
			ExtActBpmLog bpmlog = new ExtActBpmLog();
			if(processInstance!=null) {
				bpmlog.setBusinessKey(processInstance.getBusinessKey());
				bpmlog.setProcName(processInstance.getName());
			}
//			bpmlog.setOpStatus(opStatus);
			bpmlog.setOpTime(new Date());
//			bpmlog.setOpType(WorkFlowGlobals.BPM_OP_TYPE_1);
			bpmlog.setOpUserId(username);
			if(user!=null){
				bpmlog.setOpUserName(user.getRealname());
			}
			bpmlog.setProcInstId(processInstanceId);
			if(oConvertUtils.isNotEmpty(rejectDescription)) {
				reason = reason+"       『 "+rejectDescription+" 』";
			}
			bpmlog.setRemarks(reason);
			bpmlog.setTaskDefKey(task.getTaskDefinitionKey());
			bpmlog.setTaskId(taskId);
			bpmlog.setTaskName(task.getName());
			extActBpmLogService.save(bpmlog);
			//保存附件
			String fileList = oConvertUtils.getString(map.get("fileList"));
			saveBpmFiles(bpmlog.getId(),fileList);
		} catch (BpmException e) {
			result.error500("任务执行失败:"+e.getMessage());
			e.printStackTrace();
		} catch (ActivitiException e) {
			result.error500("任务执行失败:"+e.getMessage());
			e.printStackTrace();
			Object actObj = e.getCause();
			if(actObj!=null){
				Throwable throwable = (Throwable)actObj;
				if(throwable.getCause()!=null&&throwable.getCause() instanceof BpmException){
					result.error500("任务执行失败:"+throwable.getCause().getMessage());
				}
			}
		} catch (Exception e) {
			result.error500("任务执行失败:"+e.getMessage());
			e.printStackTrace();
			Object actObj = e.getCause();
			if(actObj!=null){
				Throwable throwable = (Throwable)actObj;
				if(throwable.getCause()!=null&&throwable.getCause() instanceof BpmException){
					result.error500("任务执行失败:"+throwable.getCause().getMessage());
				}
			}
		}
		return result;
	}

	private void saveBpmFiles(String bpmLogId,String fileList) {
		if(oConvertUtils.isNotEmpty(fileList)) {
			JSONArray arr = JSONArray.parseArray(fileList);
			if(arr!=null&&arr.size()>0) {
				for(int i=0;i<arr.size();i++) {
					ExtActBpmFile file = new ExtActBpmFile();
					JSONObject  json = arr.getJSONObject(i);
					file.setBpmLogId(bpmLogId);
					file.setFileName(json.getString("fileName"));
					file.setFilePath(json.getString("filePath"));
					file.setFileSize(json.getString("fileSize"));
					extActBpmFileService.save(file);
				}
			}
		}
	}

	private void taskCc(String ccUserNames,Task task,String username){
		if(oConvertUtils.isEmpty(ccUserNames)){
			return;
		}
		String [] ccUserNameArr = ccUserNames.split(",");
		ExtActTaskCc taskCcEntity = null;
		for(String ccUserName:ccUserNameArr){
			taskCcEntity = new ExtActTaskCc();
			taskCcEntity.setProcDefId(task.getProcessDefinitionId());
			taskCcEntity.setProcInstId(task.getProcessInstanceId());
			taskCcEntity.setExecutionId(task.getExecutionId());
			taskCcEntity.setTaskDefKey(task.getTaskDefinitionKey());
			taskCcEntity.setTaskId(task.getId());
			taskCcEntity.setTaskName(task.getName());
			taskCcEntity.setFromUserName(username);
			taskCcEntity.setCcUserName(ccUserName);
			extActTaskCcService.save(taskCcEntity);
		}
	}

	/**
     * 通过流程定义key和任务，判断任务是否是会签节点
     * 处理方法:通过解析xml文件
     * @param taskId
     * @return
     */
    private boolean checkUserTaskIsHuiQian(String taskId ,String taskkey){
    	Task task = activitiService.getTask(taskId);
    	//String taskkey = task.getTaskDefinitionKey();
    	String processkey = task.getProcessDefinitionId();
    	ProcessDefinition pd = repositoryService.getProcessDefinition(processkey);
		InputStream resourceAsStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), pd.getResourceName());
		String xmlString = StreamUtils.InputStreamTOString(resourceAsStream);
		return XmlActivitiUtil.parseXml(xmlString, taskkey);
    }

  //---update-begin-----autor:zhoujf------date:20190927-------for:并行网关停滞不前问题--------
    /**
     * 	解析xml判断下一个节点是否是并行网关
     *
     * @param taskId
     * @return
     */
    private boolean checkParallelGateway(String processkey ,String nexttaskkey){
    	ProcessDefinition pd = repositoryService.getProcessDefinition(processkey);
		InputStream resourceAsStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), pd.getResourceName());
		String xmlString = StreamUtils.InputStreamTOString(resourceAsStream);
		return XmlActivitiUtil.parseParallelGatewayFromXml(xmlString, nexttaskkey);
    }
  //---update-end-----autor:zhoujf------date:20190927-------for:并行网关停滞不前问题--------


    /**
	 *  	签收
	 * @param extActProcess
	 * @return
	 */
	@PutMapping(value = "/claim")
	public Result<Map<String,Object>> claim(@RequestBody HashMap<String, String> map,
											HttpServletRequest request) {
		Result<Map<String,Object>> result = new Result<Map<String,Object>>();
		try {
			String userId = JwtUtil.getUserNameByToken(request);
			String taskId=oConvertUtils.getString(map.get("taskId"));
			taskService.claim(taskId, userId);
			result.success("签收成功");
		} catch (Exception e) {
			e.printStackTrace();
			result.error500("签收失败，或者已被他人签收");
		}
		return result;
	}

	/**
	 *  	委托
	 * @param extActProcess
	 * @return
	 */
	@PutMapping(value = "/taskEntrust")
	public Result<Map<String,Object>> taskEntrust(@RequestBody HashMap<String, String> map,
											HttpServletRequest request) {
		Result<Map<String,Object>> result = new Result<Map<String,Object>>();
		try {
			String taskId=oConvertUtils.getString(map.get("taskId"));
			String taskAssignee=oConvertUtils.getString(map.get("taskAssignee"));
			Task task=taskService.createTaskQuery().taskId(taskId).active().singleResult();
			//判断任务是否签收没有签收需要进行签收
			if(oConvertUtils.isEmpty(task.getAssignee())) {
				String userId = JwtUtil.getUserNameByToken(request);
				taskService.claim(taskId, userId);
			}
			taskService.delegateTask(task.getId(), taskAssignee);
			result.success("委托成功");
		} catch (Exception e) {
			e.printStackTrace();
			result.error500("委托失败");
		}
		return result;
	}

	/**
	 * 	我发起的流程列表数据
	 */
	@GetMapping(value = "/myApplyProcessList")
	public Result<IPage<ProcessHisDTO>> myApplyProcessList(HttpServletRequest request) {
		Result<IPage<ProcessHisDTO>> result = new Result<IPage<ProcessHisDTO>>();
		IPage<ProcessHisDTO> pageList = new Page<ProcessHisDTO>();
		List<ProcessHisDTO> records = new ArrayList<ProcessHisDTO>();
		String processDefinitionId = request.getParameter("processDefinitionId");
		String processName = request.getParameter("processName");

		//根据此字段，查询是否完成流程
		String finishedStateQuery = request.getParameter("finishedStateQuery");

		String userid = JwtUtil.getUserNameByToken(request); // 获取当前登录用户
		HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery().startedBy(userid);
		if(oConvertUtils.isNotEmpty(processDefinitionId)){
			historicProcessInstanceQuery.processDefinitionId(processDefinitionId);
		}
		if(oConvertUtils.isNotEmpty(processName)){
            //--update--begin------author:scott-----date:20200806-----for:我发起的流程，支持流程名模糊查询---------------
			//通过流程名字模糊查询，流程定义KEYS
			List<String> processDefinitionKeys = extActProcessService.getProcessKeysByProcessName(processName);
			historicProcessInstanceQuery.processDefinitionKeyIn(processDefinitionKeys);
			//historicProcessInstanceQuery.processDefinitionName(processName);
			if(processDefinitionKeys==null || processDefinitionKeys.size()==0){
				pageList.setRecords(records);
				pageList.setTotal(0);
				result.setSuccess(true);
				result.setResult(pageList);
				return result;
			}
            //--update--end------author:scott-----date:20200806-----for:我发起的流程，支持流程名模糊查询---------------
		}
		// 分页参数
		Integer page = oConvertUtils.getInt(request.getParameter("pageNo"),1);
		Integer rows = oConvertUtils.getInt(request.getParameter("pageSize"),10);
		log.info("pageNo:" + page + " ,pageSize:" + rows);
		Integer start = (page - 1) * rows;
		//Integer end = page * rows - 1;
		ProcessHisDTO processHisDTO = null;
		List<HistoricProcessInstance> list = null;
		if(BpmGlobals.IS_UN_FINISHED.equals(finishedStateQuery)){
			//查询未完成流程（我发起的）
			list = historicProcessInstanceQuery.unfinished().orderByProcessInstanceStartTime().desc().listPage(start, rows);
		}else if(BpmGlobals.IS_FINISHED.equals(finishedStateQuery)){
			//查询已完成流程（我发起的）
			list = historicProcessInstanceQuery.finished().orderByProcessInstanceStartTime().desc().listPage(start, rows);
		}else{
			//查询全部流程（我发起的）
			list = historicProcessInstanceQuery.orderByProcessInstanceStartTime().desc().listPage(start, rows);
		}

		for(HistoricProcessInstance hi : list){
			String starttime = DateUtils.formatDate(hi.getStartTime(), "yyyy-MM-dd HH:mm:ss");
			String endtime = hi.getEndTime()==null?"":DateUtils.formatDate(hi.getEndTime(), "yyyy-MM-dd HH:mm:ss");
			long totalTimes = hi.getEndTime()==null?(Calendar.getInstance().getTimeInMillis()-hi.getStartTime().getTime()):(hi.getEndTime().getTime()-hi.getStartTime().getTime());

			long dayCount = totalTimes /(1000*60*60*24);//计算天
			long restTimes = totalTimes %(1000*60*60*24);//剩下的时间用于计于小时
			long hourCount = restTimes/(1000*60*60);//小时
			restTimes = restTimes % (1000*60*60);
			long minuteCount = restTimes / (1000*60);

			String spendTimes = dayCount+"天"+hourCount+"小时"+minuteCount+"分";
			processHisDTO = new ProcessHisDTO();
			processHisDTO.setId(hi.getId());
//			ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(hi.getProcessDefinitionId()).singleResult();
			processHisDTO.setPrcocessDefinitionName(hi.getProcessDefinitionName());
			processHisDTO.setStartUserId(hi.getStartUserId());
			if(oConvertUtils.isNotEmpty(processHisDTO.getStartUserId())) {
    			LoginUser sysUser = sysBaseAPI.getUserByName(processHisDTO.getStartUserId());
    			processHisDTO.setStartUserName(sysUser.getRealname());
    		}
			processHisDTO.setStartTime(starttime);
			processHisDTO.setEndTime(endtime);
			processHisDTO.setSpendTimes(spendTimes);
			processHisDTO.setProcessDefinitionId(hi.getProcessDefinitionId());
			processHisDTO.setProcessInstanceId(hi.getId());
			String bpmBizTitle = this.activitiService.getHisVarinst(WorkFlowGlobals.BPM_BIZ_TITLE, hi.getId());
			String bpmStatus = this.activitiService.getHisVarinst(WorkFlowGlobals.BPM_STATUS, hi.getId());

			//--update--begin------author:scott-----date:20191107-----for:作废流程、取回流程、驳回流程，显示流程状态---------------
			bpmStatus = oConvertUtils.getString(bpmStatus, hi.getDeleteReason());
			if (bpmStatus != null) {
				bpmStatus = bpmStatus.replace("发起人", "");
			}else{
				if(oConvertUtils.isNotEmpty(endtime)){
					bpmStatus = "已完成";
				}
			}
			//--update--end------author:scott-----date:20191107-----for:作废流程、取回流程、驳回流程，显示流程状态--------------

			processHisDTO.setBpmBizTitle(bpmBizTitle);
			processHisDTO.setBpmStatus(bpmStatus);
			records.add(processHisDTO);
		}

		Long size = historicProcessInstanceQuery.count();
		log.info("size：" + size);

		pageList.setRecords(records);
		pageList.setTotal(size);
		result.setSuccess(true);
		result.setResult(pageList);
		return result;
	}

	/**
	 * 	我发起的流程列表数据
	 */
	@GetMapping(value = "/historyProcessList")
	public Result<IPage<ProcessHisDTO>> historyProcessList(HttpServletRequest request) {
		Result<IPage<ProcessHisDTO>> result = new Result<IPage<ProcessHisDTO>>();
		IPage<ProcessHisDTO> pageList = new Page<ProcessHisDTO>();

		String processDefinitionId = request.getParameter("processDefinitionId");
		String processName = request.getParameter("processName");

		// 分页参数
		Integer page = oConvertUtils.getInt(request.getParameter("pageNo"),1);
		Integer rows = oConvertUtils.getInt(request.getParameter("pageSize"),10);
		Integer start = (page - 1) * rows;
		//Integer end = page * rows - 1;
		List<ProcessHisDTO> records = new ArrayList<ProcessHisDTO>();
		ProcessHisDTO processHisDTO = null;
		HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
		if(oConvertUtils.isNotEmpty(processDefinitionId)){
			historicProcessInstanceQuery.processDefinitionId(processDefinitionId);
		}
		if(oConvertUtils.isNotEmpty(processName)){
			historicProcessInstanceQuery.processDefinitionName(processName);
		}
	    List<HistoricProcessInstance> list = historicProcessInstanceQuery.orderByProcessInstanceStartTime().desc().listPage(start, rows);

		for(HistoricProcessInstance hi : list){
			String starttime = DateUtils.formatDate(hi.getStartTime(), "yyyy-MM-dd HH:mm:ss");
			String endtime = hi.getEndTime()==null?"":DateUtils.formatDate(hi.getEndTime(), "yyyy-MM-dd HH:mm:ss");
			long totalTimes = hi.getEndTime()==null?(Calendar.getInstance().getTimeInMillis()-hi.getStartTime().getTime()):(hi.getEndTime().getTime()-hi.getStartTime().getTime());

			long dayCount = totalTimes /(1000*60*60*24);//计算天
			long restTimes = totalTimes %(1000*60*60*24);//剩下的时间用于计于小时
			long hourCount = restTimes/(1000*60*60);//小时
			restTimes = restTimes % (1000*60*60);
			long minuteCount = restTimes / (1000*60);

			String spendTimes = dayCount+"天"+hourCount+"小时"+minuteCount+"分";
			processHisDTO = new ProcessHisDTO();
			processHisDTO.setId(hi.getId());
//			ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(hi.getProcessDefinitionId()).singleResult();
			processHisDTO.setPrcocessDefinitionName(hi.getProcessDefinitionName());
			processHisDTO.setStartUserId(hi.getStartUserId());
			if(oConvertUtils.isNotEmpty(processHisDTO.getStartUserId())) {
    			LoginUser sysUser = sysBaseAPI.getUserByName(processHisDTO.getStartUserId());
    			processHisDTO.setStartUserName(sysUser.getRealname());
    		}
			processHisDTO.setStartTime(starttime);
			processHisDTO.setEndTime(endtime);
			processHisDTO.setSpendTimes(spendTimes);
			processHisDTO.setProcessDefinitionId(hi.getProcessDefinitionId());
			processHisDTO.setProcessInstanceId(hi.getId());
			String bpmBizTitle = this.activitiService.getHisVarinst(WorkFlowGlobals.BPM_BIZ_TITLE, hi.getId());
            String bpmStatus = this.activitiService.getHisVarinst(WorkFlowGlobals.BPM_STATUS, hi.getId());

            //--update--begin------author:scott-----date:20191107-----for:作废流程、取回流程、驳回流程，显示流程状态---------------
            bpmStatus = oConvertUtils.getString(bpmStatus, hi.getDeleteReason());
            if (bpmStatus != null) {
                bpmStatus = bpmStatus.replace("发起人", "");
            }
            //--update--end------author:scott-----date:20191107-----for:作废流程、取回流程、驳回流程，显示流程状态--------------
            processHisDTO.setBpmStatus(bpmStatus);
			processHisDTO.setBpmBizTitle(bpmBizTitle);
			records.add(processHisDTO);
		}

		Long size = historicProcessInstanceQuery.count();
		log.info("size：" + size);

		pageList.setRecords(records);
		pageList.setTotal(size);
		result.setSuccess(true);
		result.setResult(pageList);
		return result;
	}

	/**
	 *  	我发起的流程，作废按钮
	 * @param
	 * @return
	 */
	@PutMapping(value = "/invalidProcess")
	public Result<Map<String,Object>> invalidProcess(@RequestBody HashMap<String, String> map,
											HttpServletRequest request) {
		Result<Map<String,Object>> result = new Result<Map<String,Object>>();
		try {
			String processInstanceId=oConvertUtils.getString(map.get("processInstanceId"));
			ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
			runtimeService.setVariable(pi.getProcessInstanceId(), WorkFlowGlobals.BPM_STATUS, WorkFlowGlobals.PROCESS_INVALIDPROCESS_STATUS);
			runtimeService.deleteProcessInstance(processInstanceId, "发起人流程作废");
			result.success("作废成功");
		} catch (Exception e) {
			e.printStackTrace();
			result.error500("作废失败");
		}
		return result;
	}

	/**
	 *  	我发起的流程，作废按钮(业务表单发起流程作废流程)
	 * @param
	 * @return
	 */
	@PutMapping(value = "/invalidBizProcess")
	public Result<Map<String,Object>> invalidBizProcess(@RequestBody HashMap<String, String> map,
											HttpServletRequest request) {
		Result<Map<String,Object>> result = new Result<Map<String,Object>>();
		try {
			String flowCode=oConvertUtils.getString(map.get("flowCode"));
			String dataId=oConvertUtils.getString(map.get("dataId"));
			//根据流程编码和业务key查询流程实例id
			LambdaQueryWrapper<ExtActFlowData> queryWrapperD = new LambdaQueryWrapper<ExtActFlowData>();
			queryWrapperD.eq(ExtActFlowData::getRelationCode, flowCode);
			queryWrapperD.eq(ExtActFlowData::getFormDataId, dataId);
			ExtActFlowData extActFlowData = extActFlowDataService.getOne(queryWrapperD);
			String processInstanceId = extActFlowData.getProcessInstId();
			ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
			runtimeService.setVariable(pi.getProcessInstanceId(), WorkFlowGlobals.BPM_STATUS, WorkFlowGlobals.PROCESS_INVALIDPROCESS_STATUS);
			runtimeService.deleteProcessInstance(processInstanceId, "发起人流程作废");
			result.success("作废成功");
		} catch (Exception e) {
			e.printStackTrace();
			result.error500("作废失败");
		}
		return result;
	}


	/**
	 *  	我发起的流程，流程追回按钮
	 *  	流程追回：删除流程实例，启动表单单据保留，
	 * @param
	 * @return
	 */
	@PutMapping(value = "/callBackProcess")
	public Result<Map<String,Object>> callBackProcess(@RequestBody HashMap<String, String> map,
											HttpServletRequest request) {
		Result<Map<String,Object>> result = new Result<Map<String,Object>>();
		try {
			String processInstanceId=oConvertUtils.getString(map.get("processInstanceId"));
			ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
			runtimeService.setVariable(pi.getProcessInstanceId(), WorkFlowGlobals.BPM_STATUS, WorkFlowGlobals.PROCESS_CALLBACKPROCESS_STATUS);
			runtimeService.deleteProcessInstance(processInstanceId, "发起人流程追回");
			result.success("追回成功");
		} catch (Exception e) {
			e.printStackTrace();
			result.error500("追回失败");
		}
		return result;
	}

	/**
	 *  	我的任务，选择流程驳回至发起人
	 * @param
	 * @return
	 */
	@PutMapping(value = "/callBackProcessByTaskId")
	public Result<Map<String,Object>> callBackProcessByTaskId(@RequestBody HashMap<String, String> map,
															  HttpServletRequest request) {
		Result<Map<String,Object>> result = new Result<Map<String,Object>>();
		try {

			Task task = activitiService.getTask(oConvertUtils.getString(map.get("taskId")));
			String processInstanceId=oConvertUtils.getString(task.getProcessInstanceId());
			ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
			runtimeService.setVariable(pi.getProcessInstanceId(), WorkFlowGlobals.BPM_STATUS, WorkFlowGlobals.PROCESS_CALLBACKPROCESS_STATUS);
			runtimeService.deleteProcessInstance(processInstanceId, "驳回至发起人");
			result.success("驳回成功");
		} catch (Exception e) {
			e.printStackTrace();
			result.error500("驳回失败");
		}
		return result;
	}

	/**
	 *  	我发起的流程，流程追回按钮
	 *  	流程追回：删除流程实例，启动表单单据保留，
	 * @param
	 * @return
	 */
	@PutMapping(value = "/callBackBizProcess")
	public Result<Map<String,Object>> callBackBizProcess(@RequestBody HashMap<String, String> map,
											HttpServletRequest request) {
		Result<Map<String,Object>> result = new Result<Map<String,Object>>();
		try {
			String flowCode=oConvertUtils.getString(map.get("flowCode"));
			String dataId=oConvertUtils.getString(map.get("dataId"));
			//根据流程编码和业务key查询流程实例id
			LambdaQueryWrapper<ExtActFlowData> queryWrapperD = new LambdaQueryWrapper<ExtActFlowData>();
			queryWrapperD.eq(ExtActFlowData::getRelationCode, flowCode);
			queryWrapperD.eq(ExtActFlowData::getFormDataId, dataId);
			ExtActFlowData extActFlowData = extActFlowDataService.getOne(queryWrapperD);
			String processInstanceId = extActFlowData.getProcessInstId();
			ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
			runtimeService.setVariable(pi.getProcessInstanceId(), WorkFlowGlobals.BPM_STATUS, WorkFlowGlobals.PROCESS_CALLBACKPROCESS_STATUS);
			runtimeService.deleteProcessInstance(processInstanceId, "发起人流程追回");
			result.success("追回成功");
		} catch (Exception e) {
			e.printStackTrace();
			result.error500("追回失败");
		}
		return result;
	}

	/**
	 * 	历史任务(查看所有历史任务)
	 */
	@GetMapping(value = "/taskAllHistoryList")
	public Result<IPage<TaskDTO>> taskAllHistoryList(HttpServletRequest request,
			@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
			  @RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
		Result<IPage<TaskDTO>> result = new Result<IPage<TaskDTO>>();
		Page<TaskDTO> pageList = new Page<TaskDTO>(pageNo,pageSize);
		pageList = activitiService.findAllHistoryTasks(pageList, request);
		result.setSuccess(true);
		result.setResult(pageList);
		return result;
	}

	/**
	 * 	抄送历史任务(查看所有历史任务)
	 */
	@GetMapping(value = "/taskAllCcHistoryList")
	public Result<IPage<TaskDTO>> taskAllCcHistoryList(HttpServletRequest request,
			@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
			  @RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
		Result<IPage<TaskDTO>> result = new Result<IPage<TaskDTO>>();
		Page<TaskDTO> pageList = new Page<TaskDTO>(pageNo,pageSize);
		String username = JwtUtil.getUserNameByToken(request);
		pageList = activitiService.findAllCcHistoryTasks(pageList,username, request);
		result.setSuccess(true);
		result.setResult(pageList);
		return result;
	}
}
